#!/usr/bin/env node

const { Server, IncomingMessage, ServerResponse } = require('http');
const { readFile } = require('fs');
const { resolve, normalize } = require('path');

const ApiProxy = require('./proxy');
const Mime = require('./core/mime');
const Logger = require('./core/logger');

// 常量
const DEFAULT_DIR = '.'
const DEFAULT_PATH = '/'
const DEFAULT_ENCODING = 'utf-8'
const DEFAULT_CONFIG = {
  host: '127.0.0.1',
  port: 80,
  home: 'index.html',
  dir: `${DEFAULT_DIR}${DEFAULT_PATH}`
}
const ProcessArgv = GetProcessArgv();
const Station = new Server(Request);
const ServiceStatus = {
  proxy: undefined,
  static: undefined
}
const { getType } = new Mime(require('./mime/types'));

Station.listen(ProcessArgv.port, ProcessArgv.host);
// 检测是否存在入口文件
ReadFilePlus(ProcessArgv.home, function (_err, _data) {
  if (_err) {
    Logger.warn(`未读取到入口文件，请检查运行目录${ProcessArgv.dir}是否存在入口文件${ProcessArgv.home}`);
    // 关闭服务
    Station.close();
  } else {
    const port = Number(ProcessArgv.port) === 80 ? '' : `:${ProcessArgv.port}`;
    const isOpen = parseFloat(ProcessArgv.host) === 0
    // 启动成功友情提示
    Logger.info(`静态网站启动成功,访问 http://${isOpen ? GetLIP() : ProcessArgv.host}${port} 进行查看`);
    if (isOpen) {
      Logger.info('同时你打开了外网访问权限，在局域网内可以通过ip进行访问')
    }
    // 消费buffer
    _data.toString();
    // 是否需要代理
    if (ProcessArgv.proxy) {
      ServiceStatus.proxy = ApiProxy(ProcessArgv)
    }
  }
});

/**
 * @description 获取本地ip地址，当传递0.0.0.0时需要获取ip进行访问
 */
function GetLIP() {
  const { networkInterfaces } = require('os');
  const networkInfo = networkInterfaces();
  for (const name of Object.keys(networkInfo)) {
    for (const iface of networkInfo[name]) {
      if (iface.family === 'IPv4' && !iface.internal) {
        return iface.address;
      }
    }
  }
  return 'localhost';
}

/**
 * @name 获取运行参数
 */
function GetProcessArgv() {
  const { argv } = process;
  const processArgv = {};
  for (let i = 0; i < argv.length; i++) {
    if (/^--/.test(argv[i])) {
      const configName = argv[i].substring(2);
      const nextArgv = argv[i + 1];
      processArgv[configName] = typeof nextArgv === 'string' ? /^--/.test(nextArgv) ? DEFAULT_CONFIG[configName] : nextArgv : DEFAULT_CONFIG[configName];
    }
  }
  return Object.assign({}, DEFAULT_CONFIG, processArgv);
}

/**
 * 
 * @param {*} _path 
 * @param {(_err: NodeJS.ErrnoException | null,_data: Buffer) => void} _$callback 
 */
function ReadFilePlus(_path, _$callback) {
  let path = typeof _path === 'string' ? _path : DEFAULT_PATH;
  // 处理空路径
  if (path === DEFAULT_PATH) {
    path = ProcessArgv.home;
  }
  // 正常流程
  else {
    path = `${DEFAULT_CONFIG.dir}${path}`;
  }
  // 读取文件
  readFile(GetPath(path), (_err, _data) => _$callback(_err, _data, path))
}

/**
 * @nmae 主函数
 * @param {IncomingMessage} _Req
 * @param {ServerResponse} _Res
 */
function Request(_Req, _Res) {
  // 如果是一个api，则进行代理
  // 前提要设置代理前缀才会进入请求代理检测
  if (ProcessArgv.prefix) {
    if (new RegExp(ProcessArgv.prefix).test(_Req.url)) {
      ServiceStatus.proxy(_Req, _Res);
      return;
    }
  }
  // 读取文件并响应
  ReadFilePlus(_Req.url, function (_err, _data, _path) {
    // 读取发生错误
    if (_err) {
      _Res.writeHead(404);
      _Res.end();
    }
    // 正常响应
    else {
      // 响应统一配置
      _Res.setHeader('Content-Type', `${getType(_path)};charset=${DEFAULT_ENCODING}`);
      _Res.end(_data);
    }
  });
}

/**
 * @name 组合文件完整路径
 * @param {string} _File
 */
function GetPath(_File) {
  let path = _File;
  // 是否允许查询参数
  if (ProcessArgv.q && ProcessArgv.q === 'false') {
    path = NeedInquire(path);
  }
  // 如果为一个路径
  if (/^\//.test(_File)) {
    path = normalize(`../${path}`);
  }
  return resolve(process.cwd(), ProcessArgv.dir, path);
}

/**
 * @name 查找文件的时候是否需要带上查询参数
 * @param {string} _Path
 */
function NeedInquire(_Path) {
  if (/\?/.test(_Path)) {
    _Path = _Path.split('?')[0];
  }
  return _Path;
}